package com.jieao.template.config;

import com.jieao.template.common.exception.BaseServiceException;
import com.jieao.template.entity.pub.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;

/**
 * 全局异常处理
 *
 * @author 姜兆伟
 * @className GlobalEctHandler
 * @date 2019-08-03 13:00
 */
@Slf4j
@RestControllerAdvice
public class GlobalEctHandler
{
    @ExceptionHandler(value = Exception.class)
    JsonData handleException(Exception e, HttpServletRequest req)
    {
        log.error("程序异常:", e);
        return JsonData.unknownError();
    }

    @ExceptionHandler(value = BaseServiceException.class)
    JsonData handleBaseServiceException(Exception e, HttpServletRequest req)
    {
        return JsonData.serviceError(e.getMessage());
    }

    /**
     * shiro 无权限异常
     *
     * @param ex
     * @param response
     * @return
     * @throws IOException
     */
    @ExceptionHandler(UnauthorizedException.class)
    public JsonData handleShiroException(Exception ex, HttpServletResponse response) throws IOException
    {
        return JsonData.unauthorized();
    }

    /**
     * shiro 未登录
     *
     * @param ex
     * @param response
     * @return
     * @throws IOException
     */
    @ExceptionHandler(UnauthenticatedException.class)
    public JsonData onLogin(Exception ex, HttpServletResponse response) throws IOException
    {
        return JsonData.noLogin();
    }


    /**
     * 缺少参数异常
     * getParameterName() 或 @RequestParam
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public JsonData requestMissingServletRequest(MissingServletRequestParameterException ex)
    {
        return JsonData.parameterError("缺少必要参数,参数名称为" + ex.getParameterName());
    }

    /**
     * controller方法参数上直接添加校验的异常控制
     *
     * @param e
     * @param req
     * @return
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    JsonData constraintViolationException(ConstraintViolationException e, HttpServletRequest req)
    {
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        ConstraintViolation<?> violation = violations.iterator().next();
        return JsonData.parameterError(violation.getMessage());
    }

    /**
     * get请求参数校验抛出的异常
     *
     * @param e 异常对象
     * @return 返回给前台的错误信息 (为实体类 校验时 指定的message)
     */
    @ExceptionHandler(BindException.class)
    public JsonData bindExceptionHandler(BindException e)
    {
        //获取异常中随机一个异常信息
        String defaultMessage = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
        return JsonData.parameterError(defaultMessage);
    }

    /**
     * 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
     *
     * @param e 异常对象
     * @return 返回给前台的错误信息 (为实体类 校验时 指定的message)
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonData methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e)
    {
        String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
        return JsonData.parameterError(message);
    }
}
